<?php
/**
 * Created by PhpStorm.
 * User: guokunsheng
 * Date: 2018/12/14
 * Time: 22:27
 */

namespace app\common\lib;

use app\common\cachemodel\AppConfig;
use app\common\cachemodel\AwardUser as AwardUserModel;
use app\common\cachemodel\MonthFortune;
use app\common\cachemodel\Orders as OrdersCacheModel;
use app\common\cachemodel\Recode;
use app\common\lib\astrolog\FortunesChange;
use app\common\lib\astrolog\YearFortune2023;
use app\common\lib\horoscope\HoroscopeFortune;
use app\common\model\AppLogicVersion;
use app\common\model\MessageCenter;
use app\common\model\Orders;
use app\common\model\SystemLogicVersion;
use app\common\model\User;
use app\common\model\YearFortune;
use think\Exception;
use think\Log;
use think\queue\job;
use think\Cache;
use XznsTools\cache\CacheManage;

/**
 * 月运年运消费队列
 * Class FortuneJob
 * @package app\common\lib
 */
class FortuneNewJob
{
    /**
     * 运势计算队列
     * @param job $job
     * @param $jobData
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function task1(Job $job, $jobData)
    {
        // 下单开通运势
        // $jobData = [
        //     'oid' => $oid,
        //     'order_id' => $fortune['order_id'],
        //     'unlock_type' => 1, // 解锁类型 1=>订单解锁 2=>系统赠送
        //     'recode' => $recode_info,
        //     'start_time' => $unlock_time,
        //     'type' => $fname,
        //     'status' => $fortune['status'],
        //     'push_switch' => $queueConfig['push_switch'],
        //     'version' => request()->header('version', ''),   // 版本号 该字段 可能不存在 【不存在情况下，不更新计算版本号】
        // ];

        $jobData['unlock_type'] = (int)$jobData['unlock_type'];
        // 可以根据业务需求和数据库中的最新数据,判断该任务是否仍有必要执行.
        $jobAttempts = $job->attempts();
        if ($jobAttempts > 1)
        {
            $job->delete();
        }

        $host = Util::getEcsIp();

        if ($jobData['type'] === 'year')
        {
            $logInfo = '年运';
        } else
        {
            $logInfo = '月运';
        }
        $startTime = date('Y-m-d H:i:s');
        $recode = current($jobData['recode']);
        try
        {
            $logInfo .= $jobData['start_time'][0] . "计算 开始:{$startTime} host:{$host} uid:{$recode['uid']} rid:{$recode['id']} name:{$recode['name']}";
            // 计算数据，并入库、写入缓存
            $res = $this->fireData($jobData);

            // 更新订单状态为，计算完成
            if ($jobData['unlock_type'] === 1 && $res === true)
            {
                $OrdersModel = new Orders();
                try
                {
                    //更新2.0订单缓存
                    (new OrdersCacheModel())->UpdateData($jobData['order_id'], ['status' => 4], 4);
                    //删除订单详情
                    Cache::rm(Orders::ORDER_INFO_ID . $jobData['oid']);
                    Cache::rm(Orders::ORDER_INFO_ID . $jobData['order_id']);
                    // 删除订单缓存
                    // $OrdersModel->rm_cache(['oid' => $jobData['oid'], 'del_add' => 0, 'uid' => $jobData['recode'][0]['uid']]);
                    $OrdersModel->rm_cache(['oid' => $jobData['oid'], 'del_add' => 0, 'uid' => $recode['uid']]);

                    $db_update_status = true;
                }
                catch (\Exception $e)
                {
                    $db_update_status = false;
                    //更新订单状态失败
                    $logInfo .= ' error:' . $e->getMessage() . ' file:' . $e->getFile() . ':' . $e->getLine();
                }
            } elseif (isset($jobData['aid']) && $jobData['aid'] && $res === true)
            {
                // 后台赠送时,修改状态
                try
                {
                    (new AwardUserModel())->UpdateData($recode['uid'], $jobData['aid'], $jobData['ftype'], ['status' => 1]);

                    if (in_array($jobData['ftype'], [2, 3]))
                    {
                        $jobData['ftype'] = $jobData['ftype'] + 1;
                    }
                    Cache::rm($recode['uid'] . '_' . $recode['id'] . '_award_fortune_' . $jobData['ftype']);

                    $db_update_status = true;
                }
                catch (\Exception $e)
                {
                    $db_update_status = false;
                    //更新订单状态失败
                    $logInfo .= ' error:' . $e->getMessage() . ' file:' . $e->getFile() . ':' . $e->getLine();
                }
            } elseif (in_array($jobData['unlock_type'], [3, 4], true) && $res === true)
            {
                $db_update_status = true;
            } else
            {
                $db_update_status = false;
                $logInfo .= ' error:队列异常';
            }

            if ($db_update_status === true)
            {
                //获取用户信息
                $userinfo = (new User())->getUserinfo(['id' => $recode['uid']]);
                $typeTxt = in_array($jobData['unlock_type'], [3, 4], true) ? '解锁' : '购买';
                //若开启推送开关则发送推送和消息
                if (isset($jobData['push_switch']) && $jobData['push_switch'])
                {
                    $recodeStatus = (new Recode())->getInfoById($recode['id'], ['status']);
                    $link = $recodeStatus['status']
                        ? 'fortune_for_' . $jobData['type'] . '?rid=' . $recode['id'] . '&time=' . $jobData['start_time'][0] . '&need_auth=1'
                        : "fortune_for_{$jobData['type']}_history?need_auth=2&order_id={$jobData['order_id']}&rid={$recode['id']}";

                    // PUSH推送
                    $pushRes = (new Push())->pushUserMsg($userinfo['id'],
                        "您{$typeTxt}的" . $recode['name'] . '的运势' . $jobData['start_time'][0] . '已经计算完成了，点击查看运势详情！',
                        ['target' => 'local', 'link' => $link, 'action' => 'extend']);

                    if (!$pushRes['success'])
                    {
                        // 运势计算完成推送失败
                        $logInfo .= ' error: 计算完成,推送失败 message:' . $pushRes['message'];
                    }

                    // 短信通知
                    if ($userinfo && $userinfo['tel'] != '' && config('queue.fortune_sendsms') == 1)
                    {
                        try
                        {
                            $recode_names = '「';
                            foreach ($jobData['recode'] as $re) $recode_names .= $re['name'] . '、';
                            $recode_names = rtrim($recode_names, '、');
                            $recode_names .= '」';

                            $fortune_times = $jobData['start_time'][0];

                            if (count($jobData['start_time']) > 1)
                            {
                                $fortune_times .= '至' . end($jobData['start_time']);
                            }

                            $sms_param = $recode_names . '的' . $fortune_times . '运势';

                            $alidayu = (new AppConfig())->configInfo('alidayu');
                            $sendSmsResult = sendSms($userinfo['tel'], ['orderId' => $sms_param], $alidayu['fortune_code']);

                            if (!empty($sendSmsResult) && $sendSmsResult['Code'] !== 'OK')
                            {
                                // 运势计算完成短信通知失败
                                $logInfo .= ' error: 计算完成,短信通知失败 message:' . $sendSmsResult['Message'];
                            }
                        }
                        catch (\Exception $e)
                        {
                            // 运势计算完成短信通知失败
                            $logInfo .= ' error:' . $e->getMessage() . ' file:' . $e->getFile() . ':' . $e->getLine();
                        }
                    }

                    // 消息中心添加信息
                    $messageData = [
                        'status' => 0,
                        'is_read' => 0,
                        'range' => $userinfo['id'],
                        'type' => 2,
                        'reid' => 0,
                        'cid' => 3,// 年运月运
                        'title' => '运势计算完成',
                        'content' => "您{$typeTxt}的" . $recode['name'] . '的运势' . $jobData['start_time'][0] . '已经计算完成了，点击查看运势详情！',
                        'link' => $link,
                        'target' => 'local',
                        'create_time' => time(),
                    ];
                    //添加消息
                    (new MessageCenter())->pushMessage($userinfo['id'], $messageData);
                }
                $logInfo .= ' success:' . date('Y-m-d H:i:s');

                $job->delete();
            } else
            {
                $job->delete();
                $logInfo .= ' failed:' . date('Y-m-d H:i:s');
            }
        }
        catch (Exception $e)
        {
            $logInfo .= ' error:' . $e->getMessage() . ' file:' . $e->getFile() . ':' . $e->getLine() . '订单编号:' . json_encode($jobData, true);
        }

        $logInfo .= ' jobData:' . json_encode($jobData, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        print(date('Y-m-d H:i:s') . ' ' . $logInfo);
        Log::write($logInfo, 'log', true);
    }

    /**
     * @param $jobData
     * @return bool
     * @throws exception\ApiException
     * @throws \Exception
     */
    public function fireData($jobData)
    {
        $monthFortune = new MonthFortune();
        $isYear = $jobData['type'] === 'year';
        if (isset($jobData['order_id']))
        {
            $res = true;
            // 年运计算
            if ($isYear)
            {
                $yearFortune = new YearFortune();
                $unlockType = $jobData['unlock_type'] === 1 ? 1 : 2; // 1=>订单（order_id为订单编号） 2=>赠送（order_id为赠送id）
                $fortuneUnlockYear = $yearFortune->alias('yf')
                    ->join('wechat_backup_07_18_14_43_00.app_fortune_recode_back r', 'r.id=yf.rid_back')->where('yf.type', $unlockType)->where('yf.order_id', $jobData['order_id'])
                    ->column('yf.year,r.recode_info,yf.rid_back,yf.rid', 'yf.id');

                // 获取当前月运最新的逻辑版本号
                $SystemLogicModel = new SystemLogicVersion();
                $logic_lastes = $SystemLogicModel->getVersion(['type' => 3]);
                foreach ($fortuneUnlockYear as $id => $unlockYearInfo)
                {
                    $data = [
                        'topics' => [],
                        'scores' => [],
                        'topic' => null,
                        'point' => null,
                    ];
                    $recodeInfo = \GuzzleHttp\json_decode($unlockYearInfo['recode_info'], true);
                    $recodeUniqueKey = "{$recodeInfo['type']}:{$recodeInfo['year']}:{$recodeInfo['month']}:{$recodeInfo['day']}:{$recodeInfo['hour']}:{$recodeInfo['minute']}:{$recodeInfo['timezone']}:{$recodeInfo['ew']}:{$recodeInfo['long_deg']}:{$recodeInfo['long_min']}:{$recodeInfo['ns']}:{$recodeInfo['lat_deg']}:{$recodeInfo['lat_min']}:{$recodeInfo['is_summer']}";

                    $map = [
                        'type' => 0, // 0=>年运逻辑生成 1=>订单（order_id为订单编号） 2=>赠送（order_id为赠送id）
                        'rid' => $unlockYearInfo['rid'],
                        'month' => [],
                    ];
                    $insertDataMonth = [];
                    $months = [];
                    // 存储行运盘数据
                    $astroDataList = [];
                    for ($i = 1; $i < 13; $i++)
                    {
                        // 年-月 char(7)
                        $start_time = $unlockYearInfo['year'] . '-' . str_pad($i, 2, '0', STR_PAD_LEFT);

                        $temp = $this->fireDataBase([
                            'recode' => $recodeInfo,
                            'start_time' => $start_time,
                            'type' => 'year',
                        ]);
                        // 拼装行运盘数据到一起
                        $astroDataList = array_merge($astroDataList, $temp['transits_list']);

                        $data['topics'] = array_merge($data['topics'], $temp['topics']);
                        $data['scores'] += $temp['scores'];
                        if ($data['topic'] === null) $data['topic'] = $temp['topic'];
                        if ($data['point'] === null) $data['point'] = $temp['point'];

                        $resMonthFortune = $monthFortune->batchGetRecodeFortuneMonthInfo($unlockYearInfo['rid'], [$start_time], [$recodeUniqueKey]);
                        if ($resMonthFortune && !empty($resMonthFortune[$unlockYearInfo['rid'] . ':' . $start_time][$recodeUniqueKey]))
                        {
                            $monthForData = \GuzzleHttp\json_decode(current($resMonthFortune)[$recodeUniqueKey], true);
                            if ($monthForData['type'] > 0)
                            {   // 已解锁
                                continue;
                            }
                        }

                        $insertDataMonth[] = [
                            'type' => 0,
                            'order_id' => 0,
                            'rid_back' => $unlockYearInfo['rid_back'],
                            'status' => 0,
                            'rid' => $unlockYearInfo['rid'],
                            'month' => $start_time,
                            'fortune' => \GuzzleHttp\json_encode($temp['topics']),
                        ];
                        $months[] = $start_time;
                    }

                    // 计算个人重点天象和新版年运重点数据
                    $changes = (new YearFortune2023())->getData($unlockYearInfo['year'], $recodeInfo, $astroDataList);

                    $map['month'] = ['in', $months];
                    if ($insertDataMonth)
                    {
                        $monthFortune->addFortuneForYear($insertDataMonth, $map);
                    }

                    foreach ($months as $monthItem)
                    {   // 删除运势缓存
                        CacheManage::getInstance()->setCacheConfig('fortune.fortune_month')
                            ->setCacheKeyDetail('details_v2', $recodeInfo['id'] . ':' . $monthItem)
                            ->rmCache('details_v2');
                    }

                    // 年运缓存删除
                    CacheManage::getInstance()->setCacheConfig('fortune.fortune_year')
                        ->setCacheKeyDetail('details_v2', $recodeInfo['id'] . ':' . $unlockYearInfo['year'])
                        ->rmCache('details_v2');

//                    $testAccount = ((new AppConfig())->configInfo('app'))['test_account'] ?? '';
//                    $testAccount = explode(',', $testAccount);
//                    if (in_array($recodeInfo['uid'], $testAccount, false))
//                    {   // 只有测试账号才 计算头图与雷达图信息
                    // 计算 年运头图与雷达图
                    $nianyunLeidaTouTu = HoroscopeFortune::getInstance()->setRecord($recodeInfo)->setAdvance($unlockYearInfo['year'] . '-06-30')->nianyunLeidaTouTu(true);
                    if (isset($nianyunLeidaTouTu['leida']))
                    {
                        $data['scores']['leida'] = $nianyunLeidaTouTu['leida'];
                    }
                    if (isset($nianyunLeidaTouTu['toutu']))
                    {
                        $data['scores']['toutu'] = $nianyunLeidaTouTu['toutu'];
                    }
//                    }
                    if (isset($changes['important_focus']))
                    {
                        $data['scores']['important_focus'] = $changes['important_focus'];
                    }
                    if (isset($changes['important_astro_list']))
                    {
                        $data['scores']['important_astro_list'] = $changes['important_astro_list'];
                    }

                    $yearFortune = new YearFortune();
                    $foruntData = [
                        'fortune' => \GuzzleHttp\json_encode($data['scores']),
                        'topic' => $data['topic'],
                        'point' => \GuzzleHttp\json_encode($data['point']),
                        'status' => 2,
                    ];
                    if (isset($jobData['version']) && $jobData['version'])
                    {
                        $foruntData['version'] = $jobData['version'];
                    }
                    $yearFortune->where('id', $id)->update($foruntData);

                    $logicVersionData = [
                        'rid' => $recodeInfo['id'],
                        'type' => 3,
                        'unlock_time' => $unlockYearInfo['year'],
                        'version' => $logic_lastes,
                    ];
                    // 记录解锁月运使用的逻辑版本号
                    $this->addFortuneVersion($logicVersionData);
                }
            } // 月运计算
            else
            {
                if (in_array((int)$jobData['unlock_type'], [3, 4], true))
                {
                    $thisMonth = current($jobData['start_time']);
                    $fortuneUnlockMonth = $monthFortune->alias('mf')
                        ->join('wechat_backup_07_18_14_43_00.app_fortune_recode_back r', 'r.id=mf.rid_back')->where('mf.type', $jobData['unlock_type'])->where('mf.month', $thisMonth)
                        ->column('mf.month,r.recode_info,mf.is_simpleness', 'mf.id');
                } else
                {
                    $unlockType = (int)$jobData['unlock_type'] === 1 ? 1 : 2; // 1=>订单（order_id为订单编号） 2=>赠送（order_id为赠送id）
                    $fortuneUnlockMonth = $monthFortune->alias('mf')
                        ->join('wechat_backup_07_18_14_43_00.app_fortune_recode_back r', 'r.id=mf.rid_back')->where('mf.type', $unlockType)->where('mf.order_id', $jobData['order_id'])
                        ->column('mf.month,r.recode_info,mf.is_simpleness', 'mf.id');
                }
                // 获取当前月运最新的逻辑版本号
                $SystemLogicModel = new SystemLogicVersion();
                $logic_lastes = $SystemLogicModel->getVersion(['type' => 2]);
                foreach ($fortuneUnlockMonth as $id => $unlockMonthInfo)
                {
                    $recodeInfo = \GuzzleHttp\json_decode($unlockMonthInfo['recode_info'], true);
                    $fireData = [
                        'recode' => $recodeInfo,
                        'start_time' => $unlockMonthInfo['month'],
                        'type' => 'month',
                    ];

                    $data = \GuzzleHttp\json_encode($this->fireDataBase($fireData), true);

                    $foruntData = [
                        'status' => 2,
                        'fortune' => $data,
                    ];

                    // 运势解锁数据入库
                    $monthFortune->where('id', $id)->update($foruntData);

                    // 删除运势缓存
                    CacheManage::getInstance()->setCacheConfig('fortune.fortune_month')
                        ->setCacheKeyDetail('details_v2', $recodeInfo['id'] . ':' . $unlockMonthInfo['month'] . ($unlockMonthInfo['is_simpleness'] > 0 ? ':1' : ''))
                        ->rmCache('details_v2');

                    $logicVersionData = [
                        'rid' => $recodeInfo['id'],
                        'type' => 2,
                        'unlock_time' => $unlockMonthInfo['month'],
                        'version' => $logic_lastes,
                    ];

                    // 记录解锁月运使用的逻辑版本号
                    $this->addFortuneVersion($logicVersionData);
                }
            }
        } else
        {
            $res = false;
            print('任务数据参数错误' . PHP_EOL);
            Log::write('任务数据参数错误:' . var_export($jobData, true), 'error', true);
        }

        return $res;
    }

    /**
     * 记录解锁月运使用的逻辑版本号
     * @param array $logicVersionData
     * $logicVersionData = [
     *  'rid' => $recodeInfo['id'],
     *  'type' => 2,
     *  'unlock_time' => $unlockMonthInfo['month'],
     *  'version' => $logic_lastes
     * ];
     */
    public function addFortuneVersion(array $logicVersionData): void
    {
        $logicVersionData['version'] = $logicVersionData['version']['version'] ?? 0;
        $logicVersionData['time'] = $logicVersionData['unlock_time'];
        unset($logicVersionData['unlock_time']);
        //获取当前档案逻辑版本号
        $AppLogicModel = new AppLogicVersion();
        $logic_user = $AppLogicModel->getVersion([
            'rid' => $logicVersionData['rid'],
            'type' => $logicVersionData['type'],
            'time' => $logicVersionData['time'],
        ]);
        // 新增
        if (!$logic_user)
        {
            $AppLogicModel->addVersion($logicVersionData);
        } // 更新了逻辑
        elseif ($logicVersionData['version'] && $logic_user <= $logicVersionData['version'])
        {
            $AppLogicModel->updateVersion($logicVersionData);
        }
    }

    /**
     * 只负责重新生成数据
     * @param $jobData
     * @return array|bool|mixed
     * @throws exception\ApiException
     */
    private function fireDataBase($jobData)
    {
        $isYear = $jobData['type'] == 'year';

        $data = (new FortunesChange())->jobInit($jobData['recode'], $jobData['start_time'], $jobData['type']);

        if ($isYear)
        {
            return $data;
        }
        return $data['topics'];
    }

    public function failed($data)
    {
        // 任务失败了
        print('任务失败数据：' . var_export($data, true) . PHP_EOL);
        \think\Log::write('任务失败：' . var_export($data, true), 'error', true);

        // 重新发布任务
    }
}
